import java.util.Iterator;
import java.util.LinkedList;
import java.util.Random;

public class Group {
	public LinkedList<DataUnit> DataQueue;
	private int bound;
	private int level_number = 100;
	private final int level_number_max = 1000;
	private int[] level_bound;
	private int delta;
	public int ID;
	// assume that one application corresponding to one group
	public Application app;
	public double performance_penalty[];
	public int queue_length[];
	public int queue_length_sum = 0;
	public double totally_delay = 0;
	public double totally_metric_considering_app_char = 0;
	public double omega;
	public double overdue = 0;// 记录超过了deadline的数据单元个数

	public int max_penalty_factor = 30;
	private Recorder recorder = null;

	private int step = 0;
	private int Counter = 0;

	double overdue_number = 0;

	// 冲突产生的性能损失，数据量，能耗
	double overdue_perf_de = 0;
	double overdue_size = 0;
	double overdue_energy = 0;
	// 未冲突产生的性能损失，数据量，能耗
	double unod_perf_de = 0;
	double unod_size = 0;
	double unod_energy = 0;

	double current_total_performance_penalty=0;
	// public double energy_consumption=0;
	public Group(int bound, int appType, int ID, double omega, Recorder recorder) {
		super();
		this.bound = bound;
		this.ID = ID;
		// this.omega = omega * (1.0 / bound);
		this.omega = omega;
		// omega = 1;
		performance_penalty = new double[level_number_max];
		queue_length = new int[level_number_max];

		app = new Application(appType);
		DataQueue = new LinkedList<DataUnit>();
		//如果时延等级数目大于deadline，那么将时延等级数量置为deadline
		if(this.bound<level_number)
			level_number=this.bound;
		// 划分每一个时延等级的边界（上界）
		delta = bound / level_number;// 时间等级间隔
		level_bound = new int[level_number];
		for (int i = 1; i <= level_number; i++)
			level_bound[i - 1] = i * delta;
		this.recorder = recorder;
		

		
	}

	public void refreshState(int t) {
		// 更新子队长向量和延迟惩罚向量
		// 将app新生成的数据单元添加到队列中
		// 新生成的数据包，delay=-1,level=0;
		// if (Counter == step) {
		// 如果计数器达到了步长，那么产生数据包
		DataUnit newdu = app.generateData(bound,t);
		if(newdu!=null)
		{
		newdu.arr_time = t;
		newdu.bound = bound;
		DataQueue.add(newdu);
		// System.out.println("      receive " + newdu.data.length + " byte data");
		queue_length[0] += newdu.data.length;
		}
		// 计数器清零，步长重新计算
		// Counter = 0;
		// step = nextStep();
		// }
		// Counter++;
		// 首先更新队列中每个数据单元的时延
		for (DataUnit du : DataQueue) {
			du.delay += 1;
			int new_level = (du.delay / delta);
			if (new_level >= level_number_max)
				new_level = level_number_max - 1;
			if (new_level != du.delay_level) {
				// 数据单元发生了等级跳变，跳到别的子队列中去了
				// System.err.println("    level up!");
				queue_length[du.delay_level] -= du.data.length;
				queue_length[new_level] += du.data.length;
				du.delay_level = new_level;
			}
		}
		
		// 每个时隙中都要根据当前每个子队列的队长来更新惩罚系数
	    current_total_performance_penalty=0;
		for (int i = 0; i < level_number_max; i++) {
			performance_penalty[i] = omega * Penalty.f(delta * (i + 1), bound) * queue_length[i];
			current_total_performance_penalty+=performance_penalty[i];
		}
		// performance_penalty[9]=Double.MAX_VALUE;//最后一个队列的惩罚因子应该为极大
		StringBuffer logsb = new StringBuffer();
		logsb.append("Group " + ID + " parameters:\n");
		logsb.append("Queue length: \n");
		queue_length_sum = 0;
		for (int l : queue_length) {
			queue_length_sum += l;
			logsb.append(l + " ");
		}
		logsb.append("   Current " + ID + "queue length: " + queue_length_sum + ".\n");
		logsb.append("\nPerformance penalty:\n");
		for (double p : performance_penalty)
			logsb.append(p + " ");
		logsb.append("\n");
		// recorder.recordlog(logsb);
	}

	public void sendData(int level, int size, int t, double bandwidth, double power) {
		// 发送level级别队列中的size字节数据
		Iterator<DataUnit> it = DataQueue.iterator();
		int send_size = size;
		while (it.hasNext() && size != 0) {
			DataUnit du = (DataUnit) it.next();
			if (du.delay_level == level) {
				if (du.data.length > size) {
//					System.err.println("send data unit info: "+du.bound+" "+(t-du.arr_time));
					// 如果这个数据单元中的数据比要发送的数据还要多，那么只要发这个单元里的数据
					totally_metric_considering_app_char += omega * size * Penalty.f((t - du.arr_time), du.bound);
					if ((t - du.arr_time) > du.bound) {
						// 产生了冲突
						// overdue_number+=omega * size * Penalty.f((t - du.arr_time), du.bound);

						overdue_perf_de += omega * size * Penalty.f((t - du.arr_time), du.bound);
						overdue_size += size;
						overdue_energy += (1.0 * size / bandwidth) * power;

					} else {
						// 没有产生冲突
						unod_perf_de += omega * size * Penalty.f((t - du.arr_time), du.bound);
						unod_size += size;
						unod_energy += (1.0 * size / bandwidth) * power;
					}
					// if ((t - du.arr_time) > du.bound) {
					// // totally_metric_considering_app_char += size * (t - du.arr_time) * max_penalty_factor;
					// //记录超过deadline发送的字节数
					// overdue+=size;
					// } else {
					// totally_metric_considering_app_char += size * (t - du.arr_time) * omega;
					// }
					totally_delay += 1.0 * size * (t - du.arr_time);
					// Recorder.recordlog(new StringBuffer("  " + size + " byte data@cause  delay: " + size * (t - du.arr_time) +
					// "    cause  mertic: "
					// + size * (t - du.arr_time) * omega + "\n"));
					du.data = new byte[du.data.length - size];
					queue_length[du.delay_level] -= size;
					size = 0;
					return;
				} else {
//					System.err.println("send data unit info: "+du.bound+" "+(t-du.arr_time));
					// 数据单元中的数据比要发送的数据少，发送整个数据单元
					totally_metric_considering_app_char += omega * du.data.length * Penalty.f((t - du.arr_time), du.bound);
					// if ((t - du.arr_time) > du.bound) {
					// // totally_metric_considering_app_char += du.data.length * (t - du.arr_time) * max_penalty_factor;
					// //记录超过deadline发送的字节数
					// overdue+=du.data.length;
					// } else {
					// totally_metric_considering_app_char += du.data.length * (t - du.arr_time) * omega;
					// }
					// if ((t - du.arr_time) > du.bound)
					// {
					// overdue_number+=omega * du.data.length * Penalty.f((t - du.arr_time), du.bound);;
					// }

					if ((t - du.arr_time) > du.bound) {
						// 产生了冲突
						// overdue_number+=omega * size * Penalty.f((t - du.arr_time), du.bound);

						overdue_perf_de += omega * du.data.length * Penalty.f((t - du.arr_time), du.bound);
						overdue_size += du.data.length;
						overdue_energy += (1.0 * du.data.length / bandwidth) * power;

					} else {
						// 没有产生冲突
						unod_perf_de += omega * du.data.length * Penalty.f((t - du.arr_time), du.bound);
						unod_size += du.data.length;
						unod_energy += (1.0 * du.data.length / bandwidth) * power;
					}

					totally_delay += 1.0 * du.data.length * (t - du.arr_time);
					// Recorder.recordlog(new StringBuffer("  " + du.data.length + " byte data#cause  delay: " + du.data.length *
					// (t - du.arr_time)
					// + "    cause  mertic: " + du.data.length * (t - du.arr_time) * omega + "\n"));
					size -= du.data.length;
					queue_length[du.delay_level] -= du.data.length;
					// 判断这个被发送的数据单元是否超过了deadline
					// if ((t - du.arr_time) > du.bound)
					// overdue++;
					it.remove();
				}
			}
		}
	}

	int nextStep() {
		int down = bound - (bound / 5);
		int up = bound + (bound / 5);
		return (int) (Math.random() * (down - up)) + down;
	}
}
